package edu.upc.dew.util;

import edu.upc.dew.service.exception.BusinessException;
import java.util.StringTokenizer;

public class KeycodeManager {

    private static final double DEFAULT_VALID_MINUTES = 10080;
    private static final String DELIMITER = ";";
    private static final int NUM_KEYPARTS = 3;
    public static final String LOGOUT_KEYCODE = "*";

    /**
     * Generates a key code based on the input string and the current time. The
     * key is valid for a maximum of VALID_HOURS hours
     *
     * @param key_
     * @return keyCode
     */
    public static String generateKeyCode(String key_) {
        return generateKeyCode(key_, System.currentTimeMillis());
    }

    /**
     * Checks if the keyCode is valid. The keyCode is valid for a maximum of
     * VALID_HOURS hours
     *
     * @param keyCode_ the original encrypted keycode
     * @param defaultValidMinutes
     * @return newKeyCode: encrypted, containing the original key, original
     * login time and the current time, as the last active time
     * @see com.pos.puntos.util.SimpleCipher
     */
    public static String checkKeyCode(String keyCode_,Double defaultValidMinutes) throws BusinessException {
        String retVal = null;

        try {
            String keycode = SimpleCipher.decrypt(keyCode_);
            StringTokenizer st = new StringTokenizer(keycode, DELIMITER);

            // First check that the key has the correct number of parts
            if (st.countTokens() != NUM_KEYPARTS) { throw new BusinessException("Key Code inválido"); }

            String key = st.nextToken();
            String loginT = st.nextToken();
            String lastT = st.nextToken();

            double validHrs = ((defaultValidMinutes != null) ? defaultValidMinutes : DEFAULT_VALID_MINUTES) * 1.0 / 60;

            // Compute the number of ms the key is valid for
            double millisValid = (double) 3600000 * validHrs;

            // Compute the number of ms the key has been in use
            double millisIn = (double) System.currentTimeMillis() - Double.parseDouble(lastT);

            // Check if the key is expired
            if (millisIn > (double) millisValid) {
                System.out.println("La sesion ha expirado: keycode="+keycode);
                throw new BusinessException("La sesión ha expirado, por favor ingresa nuevamente");
            } else {
                retVal = KeycodeManager.generateKeyCode(key, Long.parseLong(loginT));
            }
        } catch (BusinessException be) {
            throw be;
        } catch (Exception e) {
            throw new BusinessException("Key Code inválido");
        }

        return retVal;
    }

    /**
     * Get the key used to generate this keyCode.
     *
     * @param keyCode_ the original encrypted keycode
     * @return key: The original key, used to generate this keyCode.
     * @see com.pos.puntos.util.SimpleCipher
     */
    public static String getKey(String keyCode_) throws BusinessException {
        try {
            String keyCode = SimpleCipher.decrypt(keyCode_);
            StringTokenizer st = new StringTokenizer(keyCode, DELIMITER);

            // First check that the key has the correct number of parts
            if (st.countTokens() != NUM_KEYPARTS) { throw new BusinessException("Invalid Key!"); }
            String key = st.nextToken();
            return key;
        } catch (Exception ex) {
            throw new BusinessException("Key Code inválido");
        }
    }

    /**
     * Generates a key code based on the input key, the input login time and the
     * current time (as last active time). The key is valid until VALID_HOURS.
     * This method is used by generateKeyCode and checkKeyCode.
     *
     * @param key_ the string to use in generating this keycode
     * @param loginTime_ the original login time to use in the key.
     * @see com.pos.puntos.util.SimpleCipher
     * @return keyCode
     */
    private static String generateKeyCode(String key_, long loginTime_) throws BusinessException {
        try {
            // input key = key_ + delimiter + login time + delimiter + current time
            String key = key_ + KeycodeManager.DELIMITER
                    + loginTime_ + KeycodeManager.DELIMITER
                    + System.currentTimeMillis();

            // Encrypt the key code
            String keyCode = SimpleCipher.encrypt(key);
            return keyCode;
        } catch (Exception ex) {
            throw new BusinessException("Key Code inválido");
        }
    }
}